// learn/read_mp4_info.c
#include <stdio.h>
#include <libavformat/avformat.h>

void print_stream_info(AVStream *stream) {
    AVCodecParameters *codecpar = stream->codecpar;
    printf("Stream %d:\n", stream->index);
    printf("  Codec: %s\n", avcodec_get_name(codecpar->codec_id));
    printf("  Type: %s\n", codecpar->codec_type == AVMEDIA_TYPE_VIDEO ? "Video" : "Audio");
    printf("  Bitrate: %ld\n", codecpar->bit_rate);
    printf("  Width: %d\n", codecpar->width);
    printf("  Height: %d\n", codecpar->height);
    printf("  Sample Rate: %d\n", codecpar->sample_rate);
    printf("  Channels: %d\n", codecpar->channels);
}

// 查找并打印 udta 数据
void find_udta(AVFormatContext *fmt_ctx) {
    AVIOContext *pb = fmt_ctx->pb;
    uint32_t atom_size;
    unsigned char atom_type[5] = {0};

    // 重置读取位置到文件的开始
    avio_seek(pb, 0, SEEK_SET);
    printf("Reset current position = %ld\n", avio_tell(pb));

    while (1) {
        if (avio_feof(pb)) break; // 检查是否到达文件末尾

        atom_size = avio_rl32(pb); // 读取盒子大小
        avio_read(pb, atom_type, 4); // 读取盒子类型
        atom_type[4] = '\0'; // 结束字符串

        printf("Found atom: %s, size: %u\n", (char*)atom_type, atom_size); // 打印找到的盒子

        if (strcmp((const char*)atom_type, "moov") == 0) {
            printf("Entering 'moov' atom\n");
            // 进入 moov 盒子，查找 udta
            uint32_t moov_end = avio_tell(pb) + atom_size - 8; // 计算 moov 盒子的结束位置
            while (avio_tell(pb) < moov_end) {
                atom_size = avio_rl32(pb); // 读取盒子大小
                avio_read(pb, atom_type, 4); // 读取盒子类型
                atom_type[4] = '\0'; // 结束字符串

                printf("Found atom in moov: %s, size: %u\n", (char*)atom_type, atom_size); // 打印找到的盒子

                if (strcmp((const char*)atom_type, "udta") == 0) {
                    printf("Found 'udta' atom, size: %u\n", atom_size);
                    // 读取 udta 数据
                    uint8_t *udta_data = av_malloc(atom_size - 8); // 8 字节是大小和类型
                    avio_read(pb, udta_data, atom_size - 8);
                    // 打印 udta 数据的内容（示例）
                    printf("udta data: ");
                    for (uint32_t i = 0; i < atom_size - 8; i++) {
                        printf("%02x ", udta_data[i]);
                    }
                    printf("\n");
                    av_free(udta_data);
                } else {
                    // 跳过其他盒子
                    avio_skip(pb, atom_size - 8); // 跳过大小和类型
                }
            }
        } else {
            // 跳过其他盒子
            avio_skip(pb, atom_size - 8); // 跳过大小和类型
        }
    }
}

int main(int argc, char *argv[]) {
    if (argc < 2) {
        fprintf(stderr, "Usage: %s <input.mp4>\n", argv[0]);
        return 1;
    }

    const char *filename = argv[1];

    AVFormatContext *fmt_ctx = NULL;

    // 打开输入文件
    if (avformat_open_input(&fmt_ctx, filename, NULL, NULL) < 0) {
        fprintf(stderr, "Could not open file: %s\n", filename);
        return 1;
    }

    // 获取文件信息
    if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
        fprintf(stderr, "Could not find stream information\n");
        avformat_close_input(&fmt_ctx);
        return 1;
    }

    // 打印文件信息
    printf("Format: %s\n", fmt_ctx->iformat->name);
    printf("Duration: %ld seconds\n", fmt_ctx->duration / AV_TIME_BASE);
    printf("Bitrate: %ld\n", fmt_ctx->bit_rate);

    // 打印每个流的信息
    for (unsigned int i = 0; i < fmt_ctx->nb_streams; i++) {
        print_stream_info(fmt_ctx->streams[i]);
    }

    // 查找并打印 udta 数据
    find_udta(fmt_ctx);

    // 释放资源
    avformat_close_input(&fmt_ctx);
    return 0;
}


/*
代码说明
1. 包含头文件：包含 FFmpeg 的头文件以使用其 API。
2: 打开文件：使用 avformat_open_input 打开 MP4 文件。
3. 获取流信息：使用 avformat_find_stream_info 获取流的信息。
4. 打印信息：打印文件格式、持续时间、比特率以及每个流的细信息（如编码器、类型、比特率、分辨率等）。
5: 释放资源：在结束时释放打开的资源。

*/